package com.xxx.seckill.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wf.captcha.ArithmeticCaptcha;
import com.xxx.seckill.exception.GlobalException;
import com.xxx.seckill.pojo.TOrder;
import com.xxx.seckill.pojo.TSeckillOrder;
import com.xxx.seckill.pojo.TUser;
import com.xxx.seckill.rabbitmq.MQSenderFromSeckill;
import com.xxx.seckill.service.TGoodsService;
import com.xxx.seckill.service.TOrderService;
import com.xxx.seckill.service.TSeckillOrderService;
import com.xxx.seckill.utils.JsonUtil;
import com.xxx.seckill.validator.AccessLimit;
import com.xxx.seckill.vo.GoodsVo;
import com.xxx.seckill.vo.RespBean;
import com.xxx.seckill.vo.RespBeanEnum;
import com.xxx.seckill.vo.SeckillMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: xxx
 * @Date: 2023/1/5 20:16
 * @Description: 秒杀控制器
 */
@Slf4j
@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

    @Autowired
    private TGoodsService goodsService;
    @Autowired
    private TSeckillOrderService seckillOrderService;
    @Autowired
    private TOrderService orderService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MQSenderFromSeckill mqSenderFromSeckill;
    @Autowired
    private RedisScript<Long> redisScript;

    //内存标记
    private Map<Long, Boolean> EmptyStockMap = new HashMap<>();


    @RequestMapping(value = "/captcha", method = RequestMethod.GET)
    public void verifyCode(TUser user, Long goodsId, HttpServletResponse response) {


        if (user == null || goodsId < 0) {
            throw new GlobalException(RespBeanEnum.REQUEST_ILLEGAL);
        }
        //设置请求头为输入图片的类型
        response.setContentType("image/jpg");
        response.setHeader("Pargam", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        //生成验证码，将结果放到redis
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);
        redisTemplate.opsForValue().set("captcha:" + user.getId() + ":" + goodsId, captcha.text(), 300, TimeUnit.SECONDS);
        try {
            captcha.out(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            log.error("验证码生成失败", e.getMessage());

        }

    }


    /**
     * 秒杀获取地址
     *
     * @param user
     * @param goodsId
     * @return
     */
    @AccessLimit(second = 5, maxCount = 5, needLogin = true)
    @RequestMapping(value = "/path", method = RequestMethod.GET)
    @ResponseBody
    public RespBean getPath(TUser user, Long goodsId, String captcha, HttpServletRequest request) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }

        /*
        //接口限流
        ValueOperations valueOperations = redisTemplate.opsForValue();

        String uri = request.getRequestURI();
        //限制访问次数 5秒内访问5次
        captcha="0";
        Integer count = (Integer) valueOperations.get(uri + ":" + user.getId());
        if (count==null){
            valueOperations.set(uri + ":" + user.getId(), 1,3,TimeUnit.SECONDS);
        }else if (count<3){
            valueOperations.increment(uri + ":" + user.getId());
        }else {
            return RespBean.error(RespBeanEnum.ACCESS_LIMIT_REAHCED);
        }*/
        


        //校验验证码是否正确
        Boolean check = orderService.checkCaptcha(user, goodsId, captcha);
        if (!check) {
            return RespBean.error(RespBeanEnum.ERROR_CAPTCHA);
        }
        String str = orderService.createPath(user, goodsId);
        return RespBean.success(str);
    }


    /**
     * 获得秒杀结果
     *
     * @param user
     * @param goodsId
     * @return orderId:成功，1，秒杀失败，0，排队中
     */
    @RequestMapping(value = "/result", method = RequestMethod.GET)
    @ResponseBody
    public RespBean getResult(TUser user, Long goodsId) {
        if (user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        Long orderId = seckillOrderService.getResult(user, goodsId);
        return RespBean.success(orderId);
    }


    /**
     * 秒杀 优化后静态页面
     *
     * @param user
     * @param goodsId
     * @return
     */
    @RequestMapping(value = "/{path}/doSeckill1", method = RequestMethod.POST)
    @ResponseBody
    public RespBean doSeckill1(@PathVariable String path, TUser user, Long goodsId) {
        log.info("path=" + path);
        if (user == null) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }

        ValueOperations valueOperations = redisTemplate.opsForValue();
        Boolean check = orderService.checkPath(user, goodsId, path);
        if (!check) {
            return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
        }

        //判断受否重新抢购
        TSeckillOrder seckillOrder = ((TSeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId));
        if (seckillOrder != null) {
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }

        //内存标记，减少redis访问
        if (EmptyStockMap.get(goodsId)) {
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }


        //预减库存
        //redist命令式减库存
        //Long stock = valueOperations.decrement("seckillGoods:" + goodsId);
        Long stock = ((Long) redisTemplate.execute(redisScript, Collections.singletonList("seckillGoods:" + goodsId)));
        if (stock < 0) {
            EmptyStockMap.put(goodsId, true);
            valueOperations.increment("seckillGoods:" + goodsId);
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }

        SeckillMessage seckillMessage = new SeckillMessage(user, goodsId);
        mqSenderFromSeckill.sendSeckillMessage(JsonUtil.object2JsonStr(seckillMessage));


        // 返回0对象，前端接收0，展示正在排队中
        return RespBean.success(0);
        
        
        /*
        GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
        //判断库存
        if (goods.getStockCount()<1){
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        //判断受否重新抢购
        //TSeckillOrder seckillOrder = seckillOrderService.getOne(new QueryWrapper<TSeckillOrder>().eq("user_id", user.getId()).eq("goods_id", goodsId));
        TSeckillOrder seckillOrder= ((TSeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId));
        
        if (seckillOrder!=null){
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }
        TOrder order= orderService.seckill(user,goods);
        
        return RespBean.success(order);
         */
    }


    /**
     * 系统初始化，把商品库存数量记载到redis
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> list = goodsService.findGoodsVo();
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        //有库存商品方到redis中
        list.forEach(goodsVo -> {
            redisTemplate.opsForValue().set("seckillGoods:" + goodsVo.getId(), goodsVo.getStockCount());
            //有库存是false
            EmptyStockMap.put(goodsVo.getId(), false);
        });

    }


    /**
     * 秒杀
     *
     * @param model
     * @param user
     * @param goodsId
     * @return
     */
    @RequestMapping("/doSeckill")
    public String doSeckill(Model model, TUser user, Long goodsId) {
        if (user == null) {
            return "login";
        }
        model.addAttribute("user", user);
        GoodsVo goods = goodsService.findGoodsVoByGoodsId(goodsId);
        //判断库存
        if (goods.getStockCount() < 1) {
            model.addAttribute("errmsg", RespBeanEnum.EMPTY_STOCK);
            return "secKillFail";
        }
        //判断受否重新抢购
        TSeckillOrder seckillOrder = seckillOrderService.getOne(new QueryWrapper<TSeckillOrder>().eq("user_id", user.getId()).eq("goods_id", goodsId));
        if (seckillOrder != null) {
            model.addAttribute("errmsg", RespBeanEnum.REPEATE_ERROR.getMessage());
            return "seckillFail";
        }
        TOrder order = orderService.seckill(user, goods);
        model.addAttribute("order", order);
        model.addAttribute("goods", goods);
        return "orderDetail";
    }


}
